#
#    This file is part of the substandard lisp implementation of Standard Lisp
#    Copyright (C) 2011 Nicky Nickell
#
#    substandard lisp is free software: you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation, either version 3 of the License, or
#    (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.

import sys
import yaml

intable = yaml.load(sys.stdin.read())

def simplify(t):
  return t.lower().replace('type_','').replace('class_','')

def builtin_name(n):
  table = {'-':'_',
           '?':'qmark',
           '=':'eqmark',
           '>':'gtmark',
           '<':'ltmark'}
  for k,v in table.iteritems():
    n = n.replace(k,v)
  return n

doc = "lisp_docs['%s'] = '''%s'''\n"
arg = "lisp_arg_info['%s'] = '''%s'''\n"

lsp_func = "interpreted_builtins['%s'] = '''%s'''\n"
misc_func = '''%s\nbuiltins['%s'] = new builtin_function std_%s, %i, %s, [%s], %s\n'''

doc_synonyms = "lisp_docs['%s'] = '''synonymous with %s'''\n"
arg_synonyms = "lisp_arg_info['%s'] = lisp_arg_info['%s']\n"

lsp_func_synonyms = "interpreted_builtins['%s'] = interpreted_builtins['%s']\n"
misc_func_synonyms = "builtins['%s'] = builtins['%s']\n"

for category in intable:
  for func in intable[category]:
    this = intable[category][func]
    if 'synonyms' in this:
      synonyms = this['synonyms']
    else:
      synonyms = []

    out = ''

    for a in synonyms:
      out += doc_synonyms % (a, func)

    if 'doc' in this:
      out += doc % (func, this['doc'])

    if 'argument-types' in this or 'argument-names' in this:
      arginfo = []
      arguments_length = len(this['argument-types'])
      if 'argument-names' in this:
        arg_alias_length = len(this['argument-names'])
      else:
        arg_alias_length = 0
      for i in range(this['arity']):
        argstr = ''
        if i < arg_alias_length:
          argstr += this['argument-names'][i] + ' '
        if i < arguments_length:
          argstr += '[%s]' % simplify(this['argument-types'][i])
        arginfo.append(argstr)

      if this['arity'] == 0:
        argstr = ''
        if 'argument-names' in this:
          argstr += '%s' % this['argument-names'][0] + ' '
        if 'argument-types' in this:
          argstr += '[%s]' % simplify(this['argument-types'][0])
        arginfo = [argstr]

      if this['rest']:
        last = len(arginfo) - 1
        arginfo[last] = '[%s]' % arginfo[last]

      infostr = ', '.join(arginfo)
      out += arg % (this['name'], infostr)
      for a in synonyms:
        out += arg_synonyms % (a, this['name'])

    if this['lang'] == 'lsp':
      out += lsp_func % (this['name'], this['code'])
      for a in synonyms:
        pass
    elif this['lang'] in ['js', 'coffee']:
      if 'argument-types' in this:
        args = ','.join([a for a in this['argument-types']])
      else:
        args = ''

      if this['lang'] == 'js':
        code = '`%s`' % this['code']
      else:
        code = this['code']

      out += misc_func % (code, 
                          this['name'], 
                          builtin_name(this['name']), 
                          this['arity'], 
                          str(this['rest']).lower(), 
                          args,
                          this['ftype'])
      for a in synonyms:
        out += misc_func_synonyms % (a, this['name'])

    if 'exclude' in this or 'include' in this:
      conditions = []
      if 'exclude' in this:
        for cond in this['exclude']:
          conditions.append('!defined(%s)' % cond)
      if 'include' in this:
        for cond in this['include']:
          conditions.append('defined(%s)' % cond)

      conditions = ' | '.join(conditions)

      out = '`#if %s\n`\n%s\n`#endif\n`' % (conditions, out)

    print out

